<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/11/23
 * Time: 11:32
 */

namespace common\business;

use common\result\ActionResult;
use Yii;
use common\consts\CommonResources;
use common\models\Log;
use yii\db\ActiveRecord;
use yii\db\Exception;
use yii\db\StaleObjectException;
use yii\helpers\Json;

class DbHandler extends Handler
{
    /**
     * @var int
     */
    protected $_totalCount;

    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @return bool
     */
    public function saveRecordWithLogSafe($record, $log)
    {
        $transaction = Yii::$app->db->beginTransaction();
        try {
            if (!$record->save()) {
                $dbErrorMsg = Json::encode($record->getErrors());
                $this->addError('SaveRecordWithLog', $dbErrorMsg);
                $log->memo = $log->memo.' | '.CommonResources::ACTION_FAIL_MSG('Save', 'Record', $dbErrorMsg);
                $transaction->rollBack();
                return false;
            }
            if (!$log->save()) {
                $dbErrorMsg = Json::encode($log->getErrors());
                $this->addError('SaveRecordWithLog', $dbErrorMsg);
                $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Save', 'Record', $dbErrorMsg);
                Yii::error(CommonResources::ACTION_FAIL_MSG('Save', 'Log', $log->memo));
                $transaction->rollBack();
                return false;
            }
            $transaction->commit();
            return true;
        } catch (Exception $ex) {
            $this->addError('SaveRecordWithLog', $ex->getMessage());
            return false;
        }
    }

    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @return bool
     */
    public function saveRecordWithLogUnsafe($record, $log){
        $actionIsSuccess = true;
        if (!$record->save()) {
            $dbErrorMsg = Json::encode($record->getErrors());
            $this->addError('SaveRecordWithLog', $dbErrorMsg);
            $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Save', 'Record', $dbErrorMsg);
            $actionIsSuccess = false;
        }
        if (!$log->save()) {
            $dbErrorMsg = Json::encode($log->getErrors());
            $this->addError('SaveRecordWithLog', $dbErrorMsg);
            $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Save', 'Record', $dbErrorMsg);
            Yii::error(CommonResources::ACTION_FAIL_MSG('Save', 'Log', $log->memo));
        }
        return $actionIsSuccess;
    }

    /**
     * @param $record ActiveRecord
     * @return bool
     */
    public function saveRecordSafe($record){
        $log = new Log([
            'action' => CommonResources::ACTION_MSG('Save', 'Record'),
            'memo' => Json::encode($record->attributes),
        ]);
        return $this->saveRecordWithLogSafe($record, $log);
    }

    /**
     * @param $record ActiveRecord
     * @return bool
     */
    public function saveRecordUnsafe($record){
        $log = new Log([
            'action' => CommonResources::ACTION_MSG('Save', 'Record'),
            'memo' => Json::encode($record->attributes),
        ]);
        return $this->saveRecordWithLogUnsafe($record, $log);
    }

    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @return bool
     */
    public function deleteRecordWithLogUnsafe($record, $log){
        try {
            $actionIsSuccess = true;
            if (!$record->delete()) {
                $dbErrorMsg = Json::encode($record->getErrors());
                $this->addError('DeleteRecordWithLog', $dbErrorMsg);
                $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Delete', 'Record', $dbErrorMsg);
                $actionIsSuccess = false;
            }
            if (!$log->save()) {
                $dbErrorMsg = Json::encode($log->getErrors());
                $this->addError('DeleteRecordWithLog', $dbErrorMsg);
                $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Delete', 'Record', $dbErrorMsg);
                Yii::error(CommonResources::ACTION_FAIL_MSG('Save', 'Log', $log->memo));
            }
            return $actionIsSuccess;
        } catch (\Exception $e) {
            $dbErrorMsg = CommonHelper::getExceptionMsg($e);
            $this->addError('DeleteRecordWithLog', $dbErrorMsg);
            Yii::error(CommonResources::ACTION_FAIL_MSG('Delete', 'Record', $dbErrorMsg));
            return false;
        }
    }

    /**
     * @param $log Log
     * @return bool
     */
    public function saveLog($log){
        $actionIsSuccess = $log->save();
        if (!$actionIsSuccess) {
            $dbErrorMsg = Json::encode($log->getErrors());
            $this->addError('SaveRecordWithLog', $dbErrorMsg);
            $log->memo = $log->memo . ' | ' . CommonResources::ACTION_FAIL_MSG('Save', 'Record', $dbErrorMsg);
            Yii::error(CommonResources::ACTION_FAIL_MSG('Save', 'Log', $log->memo));
        }
        return $actionIsSuccess;
    }

    /**
     * @param $totalCount integer
     * @param $totalResult ActionResult
     * @param callback|null $writeBackHandler
     */
    protected function executeWriteBackHandlerWithTotal($totalResult, $totalCount, $writeBackHandler = null){
        if ($writeBackHandler){
            $paramArr = [
                'totalCount' => $totalCount,
                'finishCount' => $totalResult->total_count,
                'message' => $totalResult->getMessage(),
            ];
            call_user_func_array($writeBackHandler, $paramArr);
        }
    }

    /**
     * @param $totalResult ActionResult
     * @param callback|null $writeBackHandler
     */
    protected function executeWriteBackHandlerNoTotal($totalResult, $writeBackHandler = null){
        if ($writeBackHandler){
            $paramArr = [
                'totalCount' => $totalResult->total_count,
                'finishCount' => $totalResult->total_count,
                'message' => $totalResult->message,
            ];
            call_user_func_array($writeBackHandler, $paramArr);
        }
    }


    /**
     * @param $oldObj ActiveRecord
     * @param $newObj ActiveRecord
     * @param $compareArr array
     * @param $updateLog Log
     * @return ActionResult
     */
    protected function update($newObj, $oldObj, $compareArr, $updateLog = null){
        $action = Yii::t('app', 'Update');
        $modelClass = Yii::t('app', get_class($newObj));

//检查对象属性是否变化
        $compareResult = CommonHelper::compareObjectAttributes($oldObj, $newObj, $compareArr);
        if (!$compareResult->isChanged){
            return new ActionResult(true, CommonResources::OBJECT_NOT_CHANGED($modelClass), true);
        }

        //记住id不能变
//        $dbId = $oldObj->employee_id;
//        $oldObj->setAttributes($newObj->getAttributes());
        foreach ($compareArr as $attr){
            $oldObj->setAttribute($attr, $newObj->getAttribute($attr));
        }
//        $oldObj->employee_id = $dbId;
        if (!$updateLog){
            $updateLog = new Log([
                'action' => CommonResources::ACTION_NAME_MSG($action, $modelClass, CommonHelper::getPrintName($oldObj)),
                'old_content' => $compareResult->old_content,
                'new_content' => $compareResult->new_content,
                'memo' => $compareResult->message,
            ]);
        }

        $saveSuccess = $this->saveRecordWithLogUnsafe($oldObj, $updateLog);
        if ($saveSuccess){
            return new ActionResult(true, CommonResources::ACTION_NAME_MODEL_SUCCESS($action, $modelClass, CommonHelper::getPrintName($oldObj)));
        }
        else {
            return new ActionResult(false, CommonResources::ACTION_NAME_MODEL_FAIL_WITH_REASON($action, $modelClass, CommonHelper::getPrintName($oldObj), $this->getErrorsMessage()));
        }
    }

    /**
     * @param $obj ActiveRecord
     * @param $newLog Log
     * @return ActionResult
     */
    protected function create($obj, $newLog = null){
        $action = Yii::t('app', 'Create');
        $modelClass = Yii::t('app', get_class($obj));

        if (!$newLog){
            $newLog = new Log([
                'action' => CommonResources::ACTION_NAME_MSG($action, $modelClass, CommonHelper::getPrintName($obj)),
                'new_content' => Json::encode($obj->attributes),
            ]);
        }

        $saveSuccess = $this->saveRecordWithLogUnsafe($obj, $newLog);
        if ($saveSuccess){
            return new ActionResult(true, CommonResources::ACTION_NAME_MODEL_SUCCESS($action, $modelClass, CommonHelper::getPrintName($obj)));
        }
        else {
            return new ActionResult(false, CommonResources::ACTION_NAME_MODEL_FAIL_WITH_REASON($action, $modelClass, CommonHelper::getPrintName($obj), $this->getErrorsMessage()));
        }
    }

    /**
     * @param $obj ActiveRecord
     * @param $newLog Log
     * @return ActionResult
     */
    protected function delete($obj, $newLog = null){
        $action = Yii::t('app', 'Delete');
        $modelClass = Yii::t('app', get_class($obj));

        if (!$newLog){
            $newLog = new Log([
                'action' => CommonResources::ACTION_NAME_MSG($action, $modelClass, CommonHelper::getPrintName($obj)),
                'memo' => Json::encode($obj->attributes),
            ]);
        }

        $deleteSuccess = $this->deleteRecordWithLogUnsafe($obj, $newLog);
        if ($deleteSuccess){
            return new ActionResult(true, CommonResources::ACTION_NAME_MODEL_SUCCESS($action, $modelClass, CommonHelper::getPrintName($obj)));
        }
        else {
            return new ActionResult(false, CommonResources::ACTION_NAME_MODEL_FAIL_WITH_REASON($action, $modelClass, CommonHelper::getPrintName($obj), $this->getErrorsMessage()));
        }
    }

    /**
     * @param $obj Log
     * @return ActionResult
     */
    protected function log($obj){
        $action = Yii::t('app', 'Save');
        $modelClass = Yii::t('app', get_class($obj));

        $saveSuccess = $this->saveLog($obj);
        if ($saveSuccess){
            return new ActionResult(true, CommonResources::ACTION_SUCCESS_MSG($action, $modelClass));
        }
        else {
            return new ActionResult(false, CommonResources::ACTION_NAME_MODEL_FAIL_WITH_REASON($action, $modelClass, CommonHelper::getPrintName($obj), $this->getErrorsMessage()));
        }
    }
}